package fr.afcepf.atod16.groupe1.projet2.dao;

import fr.afcepf.atod16.groupe1.projet2.dto.DtoCommandeStock;
import fr.afcepf.atod16.groupe1.projet2.dto.DtoLigneCommandeStock;
import fr.afcepf.atod16.groupe1.projet2.entities.CommandeStock;
import fr.afcepf.atod16.groupe1.projet2.entities.LigneCommandeStock;
import fr.afcepf.atod16.groupe1.projet2.entities.ProduitStock;
import fr.afcepf.atod16.groupe1.projet2.enumerations.EtatLivraison;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.LockTimeoutException;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.PessimisticLockException;
import javax.persistence.Query;
import javax.persistence.QueryTimeoutException;
import javax.persistence.TransactionRequiredException;
import javax.persistence.criteria.CriteriaQuery;

/**
 * Implementation de la DAO commande avec JPA
 * @author cedric
 */
@Stateless
public class DaoCommandeStockJpa extends DaoAbstract<CommandeStock, DtoCommandeStock> implements DaoCommandeStock {

    @PersistenceContext(unitName = "projet2-ejbPU")
    private EntityManager em;

    /**
     * Surcharge la fonction de récupération de l'entityManager car le contexte
     * de persistance est injecté dans la classe.
     * @return L'entityManager
     */
    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    /**
     * Constructeur fournissant à la superclasse l'objet Class de l'entité
     */
    public DaoCommandeStockJpa() {
        super(CommandeStock.class);
    }
    
    /**
     * Surcharge la méthode abstraite pour lister les commande et leurs lignes.
     * @return La liste de commande
     */
    @Override
    public List<DtoCommandeStock> lister() {
        List<CommandeStock> entites;
        List<LigneCommandeStock> entitesLigne;
        DtoCommandeStock dto;
        DtoLigneCommandeStock dtoLigne;
        List<DtoLigneCommandeStock> dtosLignes;
        List<DtoCommandeStock> dtos = new ArrayList<DtoCommandeStock>();
        
        try {
            CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
            cq.select(cq.from(CommandeStock.class));
            entites = getEntityManager().createQuery(cq).getResultList();

            for (CommandeStock entite : entites) {
                dtosLignes = new ArrayList<DtoLigneCommandeStock>();
                dto = DaoAssembleur.createDto(entite);
                entitesLigne = entite.getLignes();
                for (LigneCommandeStock ligneCommandeStock : entitesLigne) {
                    dtoLigne = DaoAssembleur.createDto(ligneCommandeStock);
                    dtosLignes.add(dtoLigne);
                }
                dto.setLignes(dtosLignes);
                dtos.add(dto);
            }
        }
        catch(IllegalStateException e) {
            System.out.println("entity manager fermé OU requete non autorisé");
        }
        catch(IllegalArgumentException e) {
            System.out.println("probleme de criteria");
        }
        catch(QueryTimeoutException e) {
            System.out.println("query timeout");
        }
        catch(TransactionRequiredException e) {
            System.out.println("transaction required !");
        }
        catch(PessimisticLockException e) {
            System.out.println("echec de lock");
        }
        catch(LockTimeoutException e) {
            System.out.println("echec de lock");
        }
        catch(PersistenceException e) {
            System.out.println("query timeout");
        }
        
        return dtos;
    }
    
    /**
     * Surcharge la méthode abstraite pour enregistrer la commande 
     * avec ses lignes de produits
     * @param dto Le DTO Commande contenant ses produits
     * @return L'identifiant de la commande ainsi ajouté
     */
    @Override
    public Integer ajouter(DtoCommandeStock dto) {
        Integer id = null;
        try {
            CommandeStock entity = DaoAssembleur.createEntity(dto);
            getEntityManager().persist(entity);
            getEntityManager().flush();
            id = entity.getId();
            
            ProduitStock produitEntite;
            LigneCommandeStock ligneEntite;
            for (DtoLigneCommandeStock ligne : dto.getLignes()) {
                // la référence vers le produit
                produitEntite = DaoAssembleur.createEntity(ligne.getProduit());
                // les lignes de commandes
                ligneEntite = DaoAssembleur.createEntity(ligne);
                ligneEntite.setCommande(entity);
                ligneEntite.setProduit(produitEntite);
                // persist lignes commande
                getEntityManager().persist(ligneEntite);
                
                // mettre à jour stock produit
                
            }
        } catch (EntityExistsException e) {
            System.out.println("l'entité existe déja");
        } catch (TransactionRequiredException e) {
            System.out.println("ou est la transaction ?");
        } catch (PersistenceException e) {
            System.out.println("le flush a echoué");
        } catch (IllegalArgumentException e) {
            System.out.println("donnez moi une entité !");
        }
        return id;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<DtoCommandeStock> rechercherParNom(String nom) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public DtoCommandeStock rechercherParIdAvecProduit(Integer id) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public DtoCommandeStock rechercherParIdSite(Integer idSite) {
        Query query = em.createNamedQuery("rechercherParIdSite").setParameter("idSite", idSite);
        try {
            CommandeStock entite = (CommandeStock) query.getSingleResult();
            DtoCommandeStock dto = DaoAssembleur.createDto(entite);
            return dto;
        }
        catch(NoResultException e) {
            return null;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void annulerCommande(Integer id) {
        try {
            CommandeStock entite = getEntityManager().find(CommandeStock.class, id);
            entite.setEtatLivraison(EtatLivraison.BLOQUE);
        } catch (TransactionRequiredException e) {
            System.out.println("ou est la transaction ?");
        } catch (PersistenceException e) {
            System.out.println("le flush a echoué");
        } catch (IllegalArgumentException e) {
            System.out.println("donnez moi une entité !");
        }
    }

}
